package juc.volatilekey;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName : Volatile
 * @Author : hyy
 * @Date: 2020-03-11
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
class Order {
    private int id;
    private String name;
}

/**
 * 关于volatile关键字保证内存数据的可见性，实际是保证被volatile关键字修饰的变量指向的内存地址的可见性
 * 如果将volatile 关键字修饰的变量的引用地址复制给其他没有被volatile修饰的变量，那么这个新的变量并不具备可见性
 * 如：  以下代码，虽然order 和 order1 指向的是同一个地址，但是在多线程的环境下对order1的操作并没有可见性，只有order有，因为order1变量没有被volatile修饰
 *      static volatile Order order = new Order(0,"张三");
 *      static Order order1 = order;
 *
 * 线程在工作的时候会将主内存中的变量拷贝到一份到线程的高速缓存中
 * 如果变量没有被volatile关键字修饰，那么线程对变量的操作将不会立即写入到主内存中，也不会通知其他线程当前改变量的缓存失效
 * 如果变量被volatile关键字修饰，那么线程在修改工作空间的数据后，将立即写会主内存，并通知其他线程缓存失效，当其他线程再需要访问该变量的时候会从主内存中读取最新的数据
 */
public class VolatileDemo {
     static volatile Order order = new Order(0,"张三");
     static Order order1 = order;
    static CountDownLatch countDownLatch = new CountDownLatch(1);
    //static Order order = order1;
    public static void main(String[] args) throws InterruptedException {
        System.out.println(order);
        System.out.println(order);
        new Thread(() -> {
            System.out.println("t1线程开始执行");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1线程开始修改值");
            order.setId(10);
            countDownLatch.countDown();
        }, "t1").start();



        new Thread(() -> {
            System.out.println("t2线程开始执行");
            while (order.getId() == 0) {
                //System.out.println(order);
            }
            System.out.println("其他线程将值改变，t2线程得到通知，结束循环");
        }, "t2").start();

        countDownLatch.await();
        System.out.println(order);

    }
}
